#include "httpclient.h"  
#include <sys/types.h>
#include <sys/stat.h>

//#include "jsoncpp/include/json/json.h"


CHttpClient::CHttpClient(void) :
m_bDebug(false)
{
	curl_global_init(CURL_GLOBAL_ALL);
	url_head = "http://www.baidu.com";
	url_file_head="http://www.baidu.com";
}
CHttpClient* CHttpClient::GetInstance()
{
	static CHttpClient client;
	return &client;
}

CHttpClient::~CHttpClient(void)
{
	curl_global_cleanup();
}

static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
	if (itype == CURLINFO_TEXT)
	{
		//printf("[TEXT]%s\n", pData);  
	}
	else if (itype == CURLINFO_HEADER_IN)
	{
		printf("[HEADER_IN]%s\n", pData);
	}
	else if (itype == CURLINFO_HEADER_OUT)
	{
		printf("[HEADER_OUT]%s\n", pData);
	}
	else if (itype == CURLINFO_DATA_IN)
	{
		printf("[DATA_IN]%s\n", pData);
	}
	else if (itype == CURLINFO_DATA_OUT)
	{
		printf("[DATA_OUT]%s\n", pData);
	}
	return 0;
}

static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
	std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
	if (NULL == str || NULL == buffer)
	{
		return -1;
	}

	char* pData = (char*)buffer;
	str->append(pData, size * nmemb);
	return nmemb;
}

int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse,std::string token)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	if (m_bDebug)
	{
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
	}
	struct curl_slist *headers = NULL; /* init to NULL is important */
	headers = curl_slist_append(headers, "Content-Type: application/json");
	//headers = curl_slist_append(headers, token.c_str());
	//headers = curl_slist_append(headers, "Accept: application/json, */*;q=0.01");
	/* pass our list of custom made headers */
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	//curl_easy_setopt(curl, CURLOPT_HEADER, 1);
	//curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_POST, 1);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	curl_slist_free_all(headers);
	return res;
}

int CHttpClient::Get(const std::string & strUrl, std::string & strResponse)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	if (m_bDebug)
	{
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
	}
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	/**
	* 当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。
	* 如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。
	*/
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

int CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	if (m_bDebug)
	{
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
	}
	 
	//curl_easy_setopt(curl, CURLOPT_NOBODY, 1); 
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_POST, 1);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if (NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		//缺省情况就是PEM，所以无需设置，另外支持DER  
		//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");  
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

int CHttpClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	if (m_bDebug)
	{
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
	}
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if (NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

std::string CHttpClient::UTF8_To_string(const std::string & str)
{
	return str;		

	/*int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

	wchar_t * pwBuf = new wchar_t[nwLen + 1];//一定要加1，不然会出现尾巴 
	memset(pwBuf, 0, nwLen * 2 + 2);

	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char * pBuf = new char[nLen + 1];
	memset(pBuf, 0, nLen + 1);

	WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr = pBuf;

	delete[]pBuf;
	delete[]pwBuf;

	pBuf = NULL;
	pwBuf = NULL;

	return retStr;*/
	return "";
}
std::string  CHttpClient::string_To_UTF8(const std::string & str)
{
	return str;
	/*int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

	wchar_t * pwBuf = new wchar_t[nwLen + 1];//一定要加1，不然会出现尾巴 
	ZeroMemory(pwBuf, nwLen * 2 + 2);

	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char * pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);

	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr(pBuf);

	delete[]pwBuf;
	delete[]pBuf;

	pwBuf = NULL;
	pBuf = NULL;

	return retStr;*/
	return "";
}

///////////////////////////////////////////////////////////////////////////////////////////////  

static size_t DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)
{
	return fwrite(pBuffer, nSize, nMemByte, (FILE*)pParam);
}

/*static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
	//if (dltotal > -0.1 && dltotal < 0.1)
	//	return 0;
	//int nPos = (int)((dlnow / dltotal) * 100);
	//通知进度条更新下载进度  
	//::Sleep(10);  
	return 0;
}*/

int CHttpClient::DownloadFile(const std::string &urlPath, const std::string localpath,long timeout)
{
	struct stat file_info;
	int use_resume = 0;
	curl_off_t local_file_len = -1;

	if (stat(localpath.c_str(), &file_info) == 0)
	{
		local_file_len = file_info.st_size;
		use_resume = 1;
	}
	FILE *fp = fopen(localpath.c_str(), "ab+");
	if (fp == NULL) {
		return -2;
	}
	CURL* curl = curl_easy_init();
	curl_easy_setopt(curl, CURLOPT_URL, urlPath.c_str());
	//设置接收数据的回调  
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DownloadCallback);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
	//curl_easy_setopt(curl, CURLOPT_INFILESIZE, lFileSize);  
	//curl_easy_setopt(curl, CURLOPT_HEADER, 1);  
	//curl_easy_setopt(curl, CURLOPT_NOBODY, 1);  
	// 设置文件续传的位置给libcurl
	curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, use_resume ? local_file_len : 0);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
	// 设置重定向的最大次数  
	curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
	// 设置301、302跳转跟随location  
	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);  // 设置连接超时，单位秒
	//设置进度回调函数  
	//curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
	//curl_easy_getinfo(curl,  CURLINFO_CONTENT_LENGTH_DOWNLOAD, &lFileSize);  
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
	//开始执行请求  
	/*CURLcode retcCode = */
	curl_easy_perform(curl);
	//查看是否有出错信息  
	//const char* pError = curl_easy_strerror(retcCode);
	//清理curl，和前面的初始化匹配  
	curl_easy_cleanup(curl);
	fclose(fp);

	if (stat(localpath.c_str(), &file_info) == 0)
	{
		local_file_len = file_info.st_size;
	}

	return local_file_len;
}

std::string CHttpClient::UploadFile(const std::string &urlPath, const std::string fileName, std::string &strResponse)
{
	CURL* hCurl = curl_easy_init();
	if (hCurl == NULL) return "url init error";
	//也许有Expect: 100-continue，去掉它
	//curl_slist* pOptionList = NULL;
	//pOptionList = curl_slist_append(pOptionList, "Expect:");
	//curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, pOptionList);

	curl_httppost* pFormPost = NULL;
	curl_httppost* pLastElem = NULL;
	//上传文件，指定本地文件完整路径
	curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "file", CURLFORM_FILE, fileName.c_str(), CURLFORM_CONTENTTYPE, "multipart/form-data", CURLFORM_END);

	//上传自定义文件内容的文件，CURLFORM_BUFFER指定服务端文件名
	char file_info[] = "file";
	int record_length = std::string(file_info).length();
	curl_formadd(&pFormPost, &pLastElem,CURLFORM_COPYNAME, "file",CURLFORM_BUFFER, fileName.c_str(),CURLFORM_BUFFERPTR, file_info,CURLFORM_BUFFERLENGTH, record_length,CURLFORM_END);
	
	//不加一个结束的hfs服务端无法写入文件，一般不存在这种问题，这里加入只是为了测试.
	//curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "end", CURLFORM_COPYCONTENTS, "end", CURLFORM_END);
	
	curl_easy_setopt(hCurl, CURLOPT_HTTPPOST, pFormPost);
	curl_easy_setopt(hCurl, CURLOPT_URL, urlPath.c_str());
	
	curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(hCurl, CURLOPT_NOSIGNAL, 1);
	CURLcode res = curl_easy_perform(hCurl);
	curl_formfree(pFormPost);
	curl_easy_cleanup(hCurl);
	const char* pError = curl_easy_strerror(res);
	return pError;
}
